package model.param;

import domain.RawDataDO;
import lombok.Data;

import java.util.LinkedList;
import java.util.List;

/**
 * @author 刀氏春秋
 * @date 2023/5/17
 */
@Data
public class GatewayParam {
    private String assetNo;
    private List<List<Expression>> expressions = new LinkedList<>();

    /**
     * 设置参数
     *
     * @param gatewayA    总表A相数据
     * @param gatewayB    总表B相数据
     * @param gatewayC    总表C相数据
     * @param singlePhase 单相表数据
     */
    public void setParams(RawDataDO gatewayA, RawDataDO gatewayB, RawDataDO gatewayC, RawDataDO singlePhase) {
        // 由于数据点是按照时间顺序读入的，所以序号上完全对的上，由于单相表可能缺点或者产生奇异值，所以以单相表作为遍历目标
        List<Point> points = singlePhase.getPoints();
        for (int i = 0; i < points.size(); i++) {
            // 对于单相表中电流为0或空的值，直接跳过表达式创建
            Point point = points.get(i);
            if (point.getCurrent() == null || point.getVoltage() == null) continue;
            // 如果户表出现空值，直接跳过
            // 其他情况，创建表达式，y为单相表电压，xa为单相表电流，
            List<Expression> group = new LinkedList<>();
            // 首先建立A相多元线性相关表达式
            Double aVoltage = gatewayA.getPoints().get(i).getVoltage();
            Double aCurrent = gatewayA.getPoints().get(i).getCurrent();
            Double bVoltage = gatewayB.getPoints().get(i).getVoltage();
            Double bCurrent = gatewayB.getPoints().get(i).getCurrent();
            Double cVoltage = gatewayC.getPoints().get(i).getVoltage();
            Double cCurrent = gatewayC.getPoints().get(i).getCurrent();
            // 如果此时刻总表有任何一个空值，则废弃该点
            if (aVoltage == null || aCurrent == null || bVoltage == null || bCurrent == null || cVoltage == null || cCurrent == null)
                continue;
            group.add(new Expression(point.getVoltage(), aVoltage, aCurrent, point.getCurrent()));
            // 建立B相多元线性相关表达式
            group.add(new Expression(point.getVoltage(), bVoltage, bCurrent, point.getCurrent()));
            // 建立C相多元线性相关表达式
            group.add(new Expression(point.getVoltage(), cVoltage, cCurrent, point.getCurrent()));
            this.expressions.add(group);
            this.assetNo = singlePhase.getAssetNo();
        }
    }

    /**
     * 返回算法Y部分参数数组
     *
     * @return 单相表电压数组
     */
    public double[] getY() {
        double[] y = new double[expressions.size()];
        for (int i = 0; i < expressions.size(); i++) {
            // 对于单个点来说，每组表达式的y和xi是一样的，所以取0即可
            y[i] = expressions.get(i).get(0).getY();
        }
        return y;
    }

    /**
     * 检查单相表电流是否为0
     *
     * @return 单相表电流全为0，返回false，全不为零，返回true
     */
    public boolean checkCurrentIsAllZero() {
        int countNonZero = 0;
        for (List<Expression> group : this.expressions) {
            // 仅需判断一个即可，单个表达式组的单相表数据是相同的
            if (group.get(0).getXi() > 1e-5) {
                countNonZero++;
            }
        }
        return countNonZero == 0;
    }

    /**
     * 返回算法X部分参数数组
     *
     * @param gatewayPhase 目标相位，1为A相，2为B相，3为C相
     * @return 单相表电流、对应相电压-电流
     */
    public double[][] getX(int gatewayPhase) {
        double[][] x = null;
        // 检查是否全零，如果全零则不带入单相表电流值分析
        boolean isCurrentAllZero = checkCurrentIsAllZero();
        if (isCurrentAllZero) x = new double[expressions.size()][2];
        else x = new double[expressions.size()][3];
        // A相，看expression组中的第一个表达式，代入xI，xV和xi
        for (int i = 0; i < expressions.size(); i++) {
            // 第一个参数是xI，第二个是xV，第三个是xi
            x[i][0] = expressions.get(i).get(gatewayPhase - 1).getXI();
            x[i][1] = expressions.get(i).get(gatewayPhase - 1).getXV();
            // 如果全零的话则不带入xi
            if (!isCurrentAllZero)
                x[i][2] = expressions.get(i).get(gatewayPhase - 1).getXi();
        }
        // 滑动窗口整流去噪点
        // System.out.printf("data input: %s, %d%n", assetNo, expressions.size());
        return x;
    }
}
